

#include <cstdlib>
#include <signal.h>
#include "BUtils.h"

using namespace blueberry;
using namespace blueberry::utl::app;

char BAppEvent::z_ConfigFile[FILENAME_MAX];
std::set<BAppEventCallback*> * BAppEvent::ap_EventCb;
sigset_t BAppEvent::sigt_BlockedSignalSet;
volatile sig_atomic_t BAppEvent::sig_in_action;
BAppEvent * BAppEvent::Sp_Instance;
BMutex BAppEvent::Smtx_Instance;

BAppEvent::BAppEvent(const char * _zConfFile)
{
	sig_in_action = 0;
	sigaddset(&sigt_BlockedSignalSet, SIGABRT);
	sigaddset(&sigt_BlockedSignalSet, SIGSEGV);
	sigaddset(&sigt_BlockedSignalSet, SIGFPE);
	sigaddset(&sigt_BlockedSignalSet, SIGILL);
	sigaddset(&sigt_BlockedSignalSet, SIGQUIT);

	i_MaxSigNum = SIGRTMAX;
	ap_EventCb = new std::set<BAppEventCallback*>[i_MaxSigNum];
	for (int i = 0; i < i_MaxSigNum; ++i)
	{
		ap_EventCb[i].clear();
	}
	set_RestartCb.clear();

	strcpy(z_ConfigFile, _zConfFile);

	// -- Signal setup --
	SetSignal(SIGPIPE, SIG_IGN);
	SetSignal(SIGQUIT, SIG_DFL);
	//
	//	SetSignal(SIGINT, BAppEvent::SignalResHandler);
	//	SetSignal(SIGHUP, BAppEvent::SignalResHandler);
	//	SetSignal(SIGALRM, BAppEvent::SignalResHandler);
	//	SetSignal(SIGVTALRM, BAppEvent::SignalResHandler);
	//	SetSignal(SIGPROF, BAppEvent::SignalResHandler);
	//	SetSignal(SIGTERM, BAppEvent::SignalResHandler);
	//
	//	SetSignalBlocked(SIGABRT, BAppEvent::SignalHandler);
	//	SetSignalBlocked(SIGSEGV, BAppEvent::SignalHandler);
	//	SetSignalBlocked(SIGFPE, BAppEvent::SignalHandler);
	//	SetSignalBlocked(SIGILL, BAppEvent::SignalHandler);
	//	SetSignalBlocked(SIGQUIT, BAppEvent::SignalHandler);

	//SetSignal2(SIGKILL, BAppEvent::SignalResHandler2);
	SetSignal2(SIGINT, BAppEvent::SignalResHandler2);
	SetSignal2(SIGHUP, BAppEvent::SignalResHandler2);
	SetSignal2(SIGALRM, BAppEvent::SignalResHandler2);
	SetSignal2(SIGVTALRM, BAppEvent::SignalResHandler2);
	SetSignal2(SIGPROF, BAppEvent::SignalResHandler2);
	SetSignal2(SIGTERM, BAppEvent::SignalResHandler2);

	SetSignalBlocked2(SIGABRT, BAppEvent::SignalHandler2);
	SetSignalBlocked2(SIGSEGV, BAppEvent::SignalHandler2);
	SetSignalBlocked2(SIGFPE, BAppEvent::SignalHandler2);
	SetSignalBlocked2(SIGILL, BAppEvent::SignalHandler2);
	SetSignalBlocked2(SIGQUIT, BAppEvent::SignalHandler2);

}

BAppEvent::~BAppEvent()
{
	if (Sp_Instance)
		delete Sp_Instance;
}

void BAppEvent::SetRestartTime(int _iDay, int _iHour, int _iMin)
{
	i_RestartDay = _iDay;
	i_RestartHour = _iHour;
	i_RestartMin = _iMin;
}

BAppEvent * BAppEvent::GetInstance(const char * _zConfFile)
{
	if (Sp_Instance == NULL)
	{
		BLock<BMutex> mMutex(Smtx_Instance);

		if (Sp_Instance == NULL) // check for NULL twice
		{
			Sp_Instance = new BAppEvent(_zConfFile);
		}
	}

	return Sp_Instance;
}

void BAppEvent::SetSignal(int _iSigNum, void(*_fpSighndlr)(int))
{
	struct sigaction stSigAct, stSigOldAct;

	stSigAct.sa_handler = _fpSighndlr;
	sigemptyset(&stSigAct.sa_mask);
	stSigAct.sa_flags = SA_RESTART;

	sigaction(_iSigNum, &stSigAct, &stSigOldAct);
	//cout << "Signal set for : " << _iSigNum << endl;
}
void BAppEvent::SetSignalBlocked(int _iSigNum, void(*_fpSighndlr)(int))
{
	struct sigaction stSigAct, stSigOldAct;

	stSigAct.sa_handler = _fpSighndlr;
	sigemptyset(&stSigAct.sa_mask);
	stSigAct.sa_mask = sigt_BlockedSignalSet;
	stSigAct.sa_flags = SA_RESTART;

	sigaction(_iSigNum, &stSigAct, &stSigOldAct);

	//cout << "Signal blocked-set for : " << _iSigNum << endl;
}

void BAppEvent::SetSignal2(int _iSigNum, void(*_fpSighndlr)(int, siginfo_t *, void *))
{
	struct sigaction stSigAct, stSigOldAct;

	stSigAct.sa_sigaction = _fpSighndlr;
	sigemptyset(&stSigAct.sa_mask);
	stSigAct.sa_flags = SA_RESTART | SA_SIGINFO;

	sigaction(_iSigNum, &stSigAct, &stSigOldAct);
	//cout << "Signal2 set for : " << _iSigNum << endl;
}
void BAppEvent::SetSignalBlocked2(int _iSigNum, void(*_fpSighndlr)(int, siginfo_t *, void *))
{
	struct sigaction stSigAct, stSigOldAct;

	stSigAct.sa_sigaction = _fpSighndlr;
	sigemptyset(&stSigAct.sa_mask);
	stSigAct.sa_mask = sigt_BlockedSignalSet;
	stSigAct.sa_flags = SA_RESTART | SA_SIGINFO;

	sigaction(_iSigNum, &stSigAct, &stSigOldAct);

	//cout << "Signal2 blocked-set for : " << _iSigNum << endl;
}

void BAppEvent::UnSetSignal(int _iSigNum)
{
	struct sigaction stSigAct, stSigOldAct;

	stSigAct.sa_handler = SIG_DFL;
	sigemptyset(&stSigAct.sa_mask);
	stSigAct.sa_flags = SA_RESTART;

	sigaction(_iSigNum, &stSigAct, &stSigOldAct);

}

void BAppEvent::RegisterForEvent(int _iSigNum, BAppEventCallback * _pCb)
{
	BLock<BMutex> mMutex(Smtx_Instance);

	if (_iSigNum == APP_EVNT_SIG_ALL)
	{
		for (int i = 0; i < i_MaxSigNum; ++i)
		{
			ap_EventCb[i].insert(_pCb);
		}
	}
	else if (_iSigNum == APP_EVNT_SIG_RES)
	{
		ap_EventCb[SIGINT].insert(_pCb);
		ap_EventCb[SIGHUP].insert(_pCb);
		ap_EventCb[SIGALRM].insert(_pCb);
		ap_EventCb[SIGVTALRM].insert(_pCb);
		ap_EventCb[SIGPROF].insert(_pCb);
		ap_EventCb[SIGTERM].insert(_pCb);
	}
	else if (_iSigNum == APP_EVNT_SIG_CORE)
	{
		ap_EventCb[SIGABRT].insert(_pCb);
		ap_EventCb[SIGSEGV].insert(_pCb);
		ap_EventCb[SIGFPE].insert(_pCb);
		ap_EventCb[SIGILL].insert(_pCb);
		ap_EventCb[SIGQUIT].insert(_pCb);
	}
	else if (_iSigNum > 0 && _iSigNum < i_MaxSigNum)
	{
		ap_EventCb[_iSigNum].insert(_pCb);
	}

	set_RestartCb.insert(_pCb);
}

void BAppEvent::ForceRestart(const char * _zReason, int _iWaitIntvl)
{
	BLock<BMutex> mMutex(Smtx_Instance);

	cout << "#####################################################################################" << endl;
	cout << "## COMPONENT SELF-FORCE RESTART : " << _zReason << endl;
	cout << "#####################################################################################" << endl;
	cout << "Waiting for " << _iWaitIntvl << " secs..." << endl;
	sleep(_iWaitIntvl);

	char zBinPath[FILENAME_MAX];
	char zBinName[FILENAME_MAX];
	int iLen = readlink("/proc/self/exe", zBinPath, 512);
	if (iLen != -1)
		zBinPath[iLen] = 0;

	char * pTok;
	pTok = strtok(zBinPath, "/");
	while (pTok != NULL)
	{
		strcpy(zBinName, pTok);
		pTok = strtok(NULL, "/");
	}

	pid_t pid, sid;

	// cleanup data
	set<BAppEventCallback*>::iterator ite = set_RestartCb.begin();
	set<BAppEventCallback*>::iterator iteEnd = set_RestartCb.end();
	while (ite != iteEnd)
	{
		(*ite)->OnAppEvent(APP_EVNT_SIG_ALL);
		++ite;
	}

	pid = fork();
	if (pid == 0)
	{
		int iPPId = getppid();
		char zProc[16];
		sprintf(zProc, "/proc/%i", iPPId);
		while ((access(zProc, F_OK) != -1))
		{
			sleep(2); // sleep for 2 secs
		}
		pid_t new_pid = fork();
		if (new_pid == 0)
		{
			char * argv[256];
			argv[0] = zBinName;
			argv[1] = NULL;
			setsid(); /* obtain a new process group */
			for (int i = getdtablesize(); i >= 0; --i)
				close(i); /* close all descriptors */
			sleep(90); // sleep for 90 secs

			char zFileName[512];
			sprintf(zFileName, "../log/%s_nohup.out", zBinName);

			//int defout = dup(STDOUT_FILENO);
			int fd = open(zFileName, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
			lseek(fd, 0, SEEK_END);
			char zBuff[128];
			iLen = sprintf(zBuff, "Std Out Put redircting %d \n", fd);
			write(fd, zBuff, iLen);
			dup2(fd, STDOUT_FILENO); // redirect output to the file
			dup2(fd, STDERR_FILENO);
			close(fd);

			execv(argv[0], argv);
		}
		if (new_pid > 0)
		{
			exit(EXIT_SUCCESS);
		}
	}
	else if (pid < 0) //failed to fork
	{
		cout << "Failed restart attempt" << endl;
	}
	else if (pid > 0) // parent

	{
		cout << "Restarting component" << endl;
		exit(EXIT_SUCCESS);
	}
	umask(0);

	sid = setsid();
	if (sid < 0)
	{
		exit(EXIT_FAILURE);
	}
}

void BAppEvent::CheckRestart()
{
	struct tm *Sys_Time = NULL;
	time_t Timeval = time(0);
	Sys_Time = localtime(&Timeval);

	int iSysHour, iSysMin, iSysWday;
	iSysHour = Sys_Time->tm_hour;
	iSysMin = Sys_Time->tm_min;
	iSysWday = Sys_Time->tm_wday;

	if (i_RestartDay > 0)//if weekly restart
	{
		if (iSysWday != i_RestartDay) // if not restart today
			return;
	}

	if ((iSysHour == i_RestartHour) && (i_RestartMin == iSysMin))
	{
		BLock<BMutex> mMutex(Smtx_Instance);

		char zBinPath[FILENAME_MAX];
		char zBinName[FILENAME_MAX];
		int iLen = readlink("/proc/self/exe", zBinPath, 512);
		if (iLen != -1)
			zBinPath[iLen] = 0;

		char * pTok;
		pTok = strtok(zBinPath, "/");
		while (pTok != NULL)
		{
			strcpy(zBinName, pTok);
			pTok = strtok(NULL, "/");
		}

		pid_t pid, sid;

		// cleanup data
		set<BAppEventCallback*>::iterator ite = set_RestartCb.begin();
		set<BAppEventCallback*>::iterator iteEnd = set_RestartCb.end();
		while (ite != iteEnd)
		{
			(*ite)->OnAppEvent(APP_EVNT_SIG_ALL);
			++ite;
		}

		pid = fork();
		if (pid == 0)
		{
			int iPPId = getppid();
			char zProc[16];
			sprintf(zProc, "/proc/%i", iPPId);
			while ((access(zProc, F_OK) != -1))
			{
				sleep(2); // sleep for 2 secs
			}
			pid_t new_pid = fork();
			if (new_pid == 0)
			{
				char * argv[256];
				argv[0] = zBinName;
				argv[1] = NULL;
				setsid(); /* obtain a new process group */
				for (int i = getdtablesize(); i >= 0; --i)
					close(i); /* close all descriptors */
				sleep(90); // sleep for 90 secs

				char zFileName[512];
				sprintf(zFileName, "../log/%s_nohup.out", zBinName);

				//int defout = dup(STDOUT_FILENO);
				int fd = open(zFileName, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
				lseek(fd, 0, SEEK_END);
				char zBuff[128];
				iLen = sprintf(zBuff, "Std Out Put redircting %d \n", fd);
				write(fd, zBuff, iLen);
				dup2(fd, STDOUT_FILENO); // redirect output to the file
				dup2(fd, STDERR_FILENO);
				close(fd);

				execv(argv[0], argv);
			}
			if (new_pid > 0)
			{
				exit(EXIT_SUCCESS);
			}
		}
		else if (pid < 0) //failed to fork
		{
			cout << "Failed restart attempt" << endl;
		}
		else if (pid > 0) // parent

		{
			cout << "Restarting component" << endl;
			exit(EXIT_SUCCESS);
		}
		umask(0);

		sid = setsid();
		if (sid < 0)
		{
			exit(EXIT_FAILURE);
		}
	}

}

void BAppEvent::SignalHandler(int _iSignal)
{
	if (sig_in_action)
	{
		//raise(_iSignal);
		std::cout << "Interrupting Signal avoided : " << _iSignal << std::endl;
		return;
	}

	sig_in_action = 1;

	time_t tp;
	struct tm stTm;
	timeval tv;
	char z_TimeStamp[32];

	time(&tp);
	gettimeofday(&tv, NULL);
	strftime(z_TimeStamp, 30, "%Y-%m-%d %H:%M:%S.", localtime_r(&tp, &stTm));
	sprintf(z_TimeStamp + 20, "%03ld", tv.tv_usec);
	z_TimeStamp[23] = 0;

	std::cout << " Signal Received. [Signal=" << _iSignal << "] [Time=" << z_TimeStamp << "]" << std::endl;

	char zBinPath[FILENAME_MAX];
	char zBinName[FILENAME_MAX];
	int iLen = readlink("/proc/self/exe", zBinPath, 512);
	if (iLen != -1)
		zBinPath[iLen] = 0;

	//cout << "Bin path " << zBinPath << endl;

	char * pTok;
	pTok = strtok(zBinPath, "/");
	while (pTok != NULL)
	{
		//cout << "[" << pTok << "]";
		strcpy(zBinName, pTok);
		pTok = strtok(NULL, "/");
	}

	//cout << "Bin name " << zBinName << endl;

	// do cleaning
	// callbacks
	set<BAppEventCallback*>::iterator ite = ap_EventCb[_iSignal].begin();
	set<BAppEventCallback*>::iterator iteEnd = ap_EventCb[_iSignal].end();
	while (ite != iteEnd)
	{
		(*ite)->OnAppEvent(_iSignal);
		++ite;
	}

	// restart ???
	//	ConfigFile cFile(z_ConfigFile);
	//	if (atoi(cFile.GetValue("IS_RESTART_ENABLED")))
	//	{
	//		cout << "Trying to restart. SigNum=" << _iSignal << endl;

	pid_t pid, sid;
	pid = fork();
	if (pid == 0)
	{
		int iPPId = getppid();
		char zProc[16];
		sprintf(zProc, "/proc/%i", iPPId);
		while ((access(zProc, F_OK) != -1))
		{
			sleep(2); // sleep for 2 secs
		}
		sleep(2); // sleep for 2 secs

		pid_t new_pid = fork();
		if (new_pid == 0)
		{
			char * argv[128];
			argv[0] = zBinName;
			argv[1] = const_cast<char*>("-R");
			argv[2] = NULL;
			setsid(); /* obtain a new process group */
			for (int i = getdtablesize(); i >= 0; --i)
				close(i); /* close all descriptors */

			char zFileName[256];
			sprintf(zFileName, "../log/%s_nohup.out", zBinName);

			//int defout = dup(STDOUT_FILENO);
			int fd = open(zFileName, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
			lseek(fd, 0, SEEK_END);
			char zBuff[128];
			iLen = sprintf(zBuff, "Std Out Put redircting %d \n", fd);
			write(fd, zBuff, iLen);
			dup2(fd, STDOUT_FILENO); // redirect output to the file
			dup2(fd, STDERR_FILENO);
			close(fd);

			UnSetSignal(_iSignal);

			execv(argv[0], argv);
		}
		if (new_pid > 0)
		{
			exit(EXIT_SUCCESS);
		}
	}
	else if (pid < 0) //failed to fork
	{
		cout << "Failed restart attempt" << endl;
	}
	else if (pid > 0) // parent
	{
		cout << "Restarting component" << endl;

		UnSetSignal(_iSignal);
		raise(_iSignal);
	}

	umask(0);

	sid = setsid();
	if (sid < 0)
	{
		UnSetSignal(_iSignal);
		raise(_iSignal);
	}
	//	}
	//	else
	//	{
	//		std::cout << " Restart not enabled. System EXIT !!! " << std::endl;
	//		UnSetSignal(_iSignal);
	//		raise(_iSignal);
	//	}

}

void BAppEvent::SignalResHandler(int _iSignal)
{
	if (sig_in_action)
	{
		//raise(_iSignal);
		std::cout << "Interrupting Signal avoided : " << _iSignal << std::endl;
		return;
	}

	sig_in_action = 1;

	time_t tp;
	struct tm stTm;
	timeval tv;
	char z_TimeStamp[32];

	time(&tp);
	gettimeofday(&tv, NULL);
	strftime(z_TimeStamp, 30, "%Y-%m-%d %H:%M:%S.", localtime_r(&tp, &stTm));
	sprintf(z_TimeStamp + 20, "%03ld", tv.tv_usec);
	z_TimeStamp[23] = 0;

	std::cout << " Resource Signal Received. [Signal=" << _iSignal << "] [Time=" << z_TimeStamp << "]" << std::endl;
	std::cout << " System voluntarily escaped." << std::endl;

	exit(_iSignal);
}

void BAppEvent::PrintSignalInfo(int _iSignal, siginfo_t * _stSigInfo, void * _pUContext)
{
	time_t tp;
	struct tm stTm;
	timeval tv;
	char z_TimeStamp[32];

	time(&tp);
	gettimeofday(&tv, NULL);
	strftime(z_TimeStamp, 30, "%Y-%m-%d %H:%M:%S.", localtime_r(&tp, &stTm));
	sprintf(z_TimeStamp + 20, "%03ld", tv.tv_usec);
	z_TimeStamp[23] = 0;

	std::cout << "Signal Received. [SigNo=" << _stSigInfo->si_signo << "|SigCode=" << _stSigInfo->si_code << "|ErrNo=" << _stSigInfo->si_errno << "] [Time=" << z_TimeStamp << "]" << std::endl;
	switch (_iSignal)
	{
		case SIGCHLD:
			std::cout << "Signal sent by : PID=" << _stSigInfo->si_pid << "|UID=" << _stSigInfo->si_uid << std::endl;
		break;
		case SIGILL:
		case SIGFPE:
		case SIGSEGV:
		case SIGBUS:
			printf("Address of fault : 0x%lx \n", (long) _stSigInfo->si_addr);
		break;
		case SIGPOLL:
			std::cout << "Band event : " << _stSigInfo->si_band << " file descriptor : " << _stSigInfo->si_fd << std::endl;
		default:
		break;
	}

	switch (_stSigInfo->si_code)
	{
		case SI_USER:
			std::cout << "Signal is sent by : kill or raise" << std::endl;
		break;
		case SI_KERNEL:
			std::cout << "Signal is sent by : kernel" << std::endl;
		break;
		case SI_QUEUE:
			std::cout << "Signal is sent by : sigqueue" << std::endl;
		break;
		case SI_TIMER:
			std::cout << "Signal is sent by : POSIX timer expired" << std::endl;
		break;
		case SI_MESGQ:
			std::cout << "Signal is sent by : POSIX message queue state changed" << std::endl;
		break;
		case SI_ASYNCIO:
			std::cout << "Signal is sent by : AIO completed" << std::endl;
		break;
		case SI_SIGIO:
			std::cout << "Signal is sent by : queued SIGIO" << std::endl;
		break;
		case SI_TKILL:
			std::cout << "Signal is sent by : tkill or tgkill" << std::endl;
		break;
		default:
		break;
	}
	switch (_iSignal)
	{
		case SIGILL:
		{
			switch (_stSigInfo->si_code)
			{
				case ILL_ILLOPC:
					std::cout << "Signal is sent by : SIGILL - illegal opcode" << std::endl;
				break;
				case ILL_ILLOPN:
					std::cout << "Signal is sent by : SIGILL - illegal operand" << std::endl;
				break;
				case ILL_ILLADR:
					std::cout << "Signal is sent by : SIGILL - illegal addressing mode" << std::endl;
				break;
				case ILL_ILLTRP:
					std::cout << "Signal is sent by : SIGILL - illegal trap" << std::endl;
				break;
				case ILL_PRVOPC:
					std::cout << "Signal is sent by : SIGILL - privileged opcode" << std::endl;
				break;
				case ILL_PRVREG:
					std::cout << "Signal is sent by : SIGILL - privileged register" << std::endl;
				break;
				case ILL_COPROC:
					std::cout << "Signal is sent by : SIGILL - coprocessor error" << std::endl;
				break;
				case ILL_BADSTK:
					std::cout << "Signal is sent by : SIGILL - internal stack error" << std::endl;
				break;
				default:
				break;
			}
		}
		break;
		case SIGFPE:
		{
			switch (_stSigInfo->si_code)
			{
				case FPE_INTDIV:
					std::cout << "Signal is sent by : SIGFPE - integer divide by zero" << std::endl;
				break;
				case FPE_INTOVF:
					std::cout << "Signal is sent by : SIGFPE - integer overflow" << std::endl;
				break;
				case FPE_FLTDIV:
					std::cout << "Signal is sent by : SIGFPE - floating-point divide by zero" << std::endl;
				break;
				case FPE_FLTOVF:
					std::cout << "Signal is sent by : SIGFPE - floating-point overflow" << std::endl;
				break;
				case FPE_FLTUND:
					std::cout << "Signal is sent by : SIGFPE - floating-point underflow" << std::endl;
				break;
				case FPE_FLTRES:
					std::cout << "Signal is sent by : SIGFPE - floating-point inexact result" << std::endl;
				break;
				case FPE_FLTINV:
					std::cout << "Signal is sent by : SIGFPE - floating-point invalid operation" << std::endl;
				break;
				case FPE_FLTSUB:
					std::cout << "Signal is sent by : SIGFPE - subscript out of range" << std::endl;
				break;
				default:
				break;
			}
		}
		break;
		case SIGSEGV:
		{
			switch (_stSigInfo->si_code)
			{
				case SEGV_MAPERR:
					std::cout << "Signal is sent by : SIGSEGV - address not mapped to object" << std::endl;
				break;
				case SEGV_ACCERR:
					std::cout << "Signal is sent by : SIGSEGV - invalid permissions for mapped object" << std::endl;
				break;
				default:
				break;
			}
		}
		break;
		case SIGCHLD:
		{
			switch (_stSigInfo->si_code)
			{
				case CLD_EXITED:
					std::cout << "Signal is sent by : SIGCHLD - child has exited" << std::endl;
				break;
				case CLD_KILLED:
					std::cout << "Signal is sent by : SIGCHLD - child was killed" << std::endl;
				break;
				case CLD_DUMPED:
					std::cout << "Signal is sent by : SIGCHLD - child terminated abnormally" << std::endl;
				break;
				case CLD_TRAPPED:
					std::cout << "Signal is sent by : SIGCHLD - traced child has trapped" << std::endl;
				break;
				case CLD_STOPPED:
					std::cout << "Signal is sent by : SIGCHLD - child has stopped" << std::endl;
				break;
				case CLD_CONTINUED:
					std::cout << "Signal is sent by : SIGCHLD - stopped child has continued" << std::endl;
				break;
				default:
				break;
			}
		}
		break;
		case SIGBUS:
		{
			switch (_stSigInfo->si_code)
			{
				case BUS_ADRALN:
					std::cout << "Signal is sent by : SIGBUS - invalid address alignment" << std::endl;
				break;
				case BUS_ADRERR:
					std::cout << "Signal is sent by : SIGBUS - nonexistent physical address" << std::endl;
				break;
				case BUS_OBJERR:
					std::cout << "Signal is sent by : SIGBUS - object-specific hardware error" << std::endl;
				break;
				default:
				break;
			}
		}
		break;
		case SIGPOLL:
		{
			switch (_stSigInfo->si_code)
			{
				case POLL_IN:
					std::cout << "Signal is sent by : SIGPOLL - data input available" << std::endl;
				break;
				case POLL_OUT:
					std::cout << "Signal is sent by : SIGPOLL - output buffers available" << std::endl;
				break;
				case POLL_MSG:
					std::cout << "Signal is sent by : SIGPOLL - input message available" << std::endl;
				break;
				case POLL_ERR:
					std::cout << "Signal is sent by : SIGPOLL - i/o error" << std::endl;
				break;
				case POLL_PRI:
					std::cout << "Signal is sent by : SIGPOLL - high priority input available" << std::endl;
				break;
				case POLL_HUP:
					std::cout << "Signal is sent by : SIGPOLL - device disconnected" << std::endl;
				break;
				default:
				break;
			}
		}
		break;
		case SIGTRAP:
		{
			switch (_stSigInfo->si_code)
			{
				case TRAP_BRKPT:
					std::cout << "Signal is sent by : SIGTRAP - process breakpoint" << std::endl;
				break;
				case TRAP_TRACE:
					std::cout << "Signal is sent by : SIGTRAP - process trace trap" << std::endl;
				break;
				default:
				break;
			}
		}
		break;
		default:
		break;
	}

	_pUContext = _pUContext;
}

void BAppEvent::SignalHandler2(int _iSignal, siginfo_t * _stSigInfo, void * _pUContext)
{
	if (sig_in_action)
	{
		std::cout << "Interrupting Signal avoided : " << _iSignal << std::endl;
		raise(_iSignal);
		return;
	}

	sig_in_action = 1;

	PrintSignalInfo(_iSignal, _stSigInfo, _pUContext);

	char zBinPath[FILENAME_MAX];
	char zBinName[FILENAME_MAX];
	int iLen = readlink("/proc/self/exe", zBinPath, 512);
	if (iLen != -1)
		zBinPath[iLen] = 0;

	//cout << "Bin path " << zBinPath << endl;

	char * pTok;
	pTok = strtok(zBinPath, "/");
	while (pTok != NULL)
	{
		//cout << "[" << pTok << "]";
		strcpy(zBinName, pTok);
		pTok = strtok(NULL, "/");
	}

	//cout << "Bin name " << zBinName << endl;

	// do cleaning
	// callbacks
	set<BAppEventCallback*>::iterator ite = ap_EventCb[_iSignal].begin();
	set<BAppEventCallback*>::iterator iteEnd = ap_EventCb[_iSignal].end();
	while (ite != iteEnd)
	{
		(*ite)->OnAppEvent(_iSignal);
		++ite;
	}

	sigprocmask(SIG_UNBLOCK, &sigt_BlockedSignalSet, NULL); // before fork

	// restart ???
	// if config file not found return to here. do not call exit!
	//ConfigFile cFile(z_ConfigFile);
	// check if config is exist
	//const char * zIsRestart = cFile.GetValue("IS_RESTART_ENABLED",true);
	//if (zIsRestart && (atoi(zIsRestart) == 1))
	//{
	//	cout << "Trying to restart. SigNum=" << _iSignal << endl;

	pid_t pid, sid;

	pid = fork();
	if (pid == 0)
	{
		int iPPId = getppid();
		char zProc[16];
		sprintf(zProc, "/proc/%i", iPPId);
		while ((access(zProc, F_OK) != -1))
		{
			sleep(2); // sleep for 2 secs
		}
		sleep(2); // sleep for 2 secs

		pid_t new_pid = fork();
		if (new_pid == 0)
		{
			char * argv[128];
			argv[0] = zBinName;
			argv[1] = const_cast<char*>("-R");
			argv[2] = NULL;
			setsid(); /* obtain a new process group */
			for (int i = getdtablesize(); i >= 0; --i)
				close(i); /* close all descriptors */

			char zFileName[256];
			sprintf(zFileName, "../log/%s_nohup.out", zBinName);

			//int defout = dup(STDOUT_FILENO);
			int fd = open(zFileName, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
			lseek(fd, 0, SEEK_END);
			char zBuff[128];
			iLen = sprintf(zBuff, "Restarting %s \n", argv[0]);
			int iLenDummy = write(fd, zBuff, iLen);
			iLenDummy = iLenDummy;
			dup2(fd, STDOUT_FILENO); // redirect output to the file
			dup2(fd, STDERR_FILENO);
			close(fd);

			execv(argv[0], argv);
		}
		if (new_pid > 0)
		{
			exit(EXIT_SUCCESS);
		}
	}
	else if (pid < 0) //failed to fork
	{
		cout << "Failed restart attempt" << endl;
	}
	else if (pid > 0) // parent
	{
		cout << "Restarting component" << endl;

		UnSetSignal(_iSignal);
		raise(_iSignal);
	}

	umask(0);

	sid = setsid();
	if (sid < 0)
	{
		UnSetSignal(_iSignal);
		raise(_iSignal);
	}
	//	}
	//	else
	//	{
	//		std::cout << " Restart not enabled. System EXIT !!! " << std::endl;
	//		UnSetSignal(_iSignal);
	//		raise(_iSignal);
	//	}

}

void BAppEvent::SignalResHandler2(int _iSignal, siginfo_t * _stSigInfo, void * _pUContext)
{
	if (sig_in_action)
	{
		//raise(_iSignal);
		std::cout << "Interrupting Signal avoided : " << _iSignal << std::endl;
		return;
	}

	sig_in_action = 1;

	PrintSignalInfo(_iSignal, _stSigInfo, _pUContext);
	std::cout << " System voluntarily escaped." << std::endl;

	exit(_iSignal);
}

void BAppEvent::IgnoreSignal(int _iSigNum)
{
	SetSignal(_iSigNum, SIG_IGN);
}

void BAppEvent::SetSignalDefaultAction(int _iSigNum)
{
	SetSignal(_iSigNum, SIG_DFL);
}
